<html>

<head>
  <meta charset="utf-8">
  <title>mybatis小工具</title>
  <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.4/lodash.min.js"></script>
  <script>;(function (root, factory) {
  if (typeof module === "object" && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory()
  } else {
    // Browser globals (root is window)
    root["parser"] = factory()
  }
}) (this,function() {
  /*
   * Generated by PEG.js 0.8.0.
   *
   * http://pegjs.majda.cz/
   */

  function peg$subclass(child, parent) {
    function ctor() { this.constructor = child; }
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
  }

  function SyntaxError(message, expected, found, offset, line, column) {
    this.message  = message;
    this.expected = expected;
    this.found    = found;
    this.offset   = offset;
    this.line     = line;
    this.column   = column;

    this.name     = "SyntaxError";
  }

  peg$subclass(SyntaxError, Error);

  function parse(input) {
    var options = arguments.length > 1 ? arguments[1] : {},

        peg$FAILED = {},

        peg$startRuleFunctions = { start: peg$parsestart },
        peg$startRuleFunction  = peg$parsestart,

        peg$c0 = peg$FAILED,
        peg$c1 = null,
        peg$c2 = function(call, properties, querybody) { call.properties = properties.properties;call.querybody=querybody.join(''); return call; },
        peg$c3 = function(call) { call.root = true; return call; },
        peg$c4 = [],
        peg$c5 = ".",
        peg$c6 = { type: "literal", value: ".", description: "\".\"" },
        peg$c7 = function(call) { return call },
        peg$c8 = function(calls) { return Array.isArray(calls) ? calls : [calls]; },
        peg$c9 = function(name, parameters) { return { call: name, parameters: parameters }},
        peg$c10 = "(",
        peg$c11 = { type: "literal", value: "(", description: "\"(\"" },
        peg$c12 = ")",
        peg$c13 = { type: "literal", value: ")", description: "\")\"" },
        peg$c14 = function(call_parameters) { return call_parameters; },
        peg$c15 = function(p) { return p },
        peg$c16 = function(first, rest) { return [first].concat(rest); },
        peg$c17 = function(parameter_list) { return parameter_list; },
        peg$c18 = function(name, value) { return {name:name,value:value[1].join('')}; },
        peg$c19 = /^[a-zA-Z0-9]/,
        peg$c20 = { type: "class", value: "[a-zA-Z0-9]", description: "[a-zA-Z0-9]" },
        peg$c21 = function(parameter) { return parameter.join('') },
        peg$c22 = "{",
        peg$c23 = { type: "literal", value: "{", description: "\"{\"" },
        peg$c24 = "}",
        peg$c25 = { type: "literal", value: "}", description: "\"}\"" },
        peg$c26 = function(properties) { return { properties: properties } },
        peg$c27 = function(properties) { return properties; },
        peg$c28 = function(name) { return { name: name }; },
        peg$c29 = function(name, properties) { return { name: name, properties: properties } },
        peg$c30 = function(name, calls, properties) { return { name: name, calls: calls, properties: properties }; },
        peg$c31 = ",",
        peg$c32 = { type: "literal", value: ",", description: "\",\"" },
        peg$c33 = /^[a-z0-9A-Z_$]/,
        peg$c34 = { type: "class", value: "[a-z0-9A-Z_$]", description: "[a-z0-9A-Z_$]" },
        peg$c35 = function(identifier) { return identifier.join(''); },
        peg$c36 = { type: "other", description: "whitespace" },
        peg$c37 = /^[ \t\n\r]/,
        peg$c38 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
        peg$c39 = function(x) {return x},
        peg$c40 = function(alias, name, jname, ctype) {return {name:name,alias:alias,type:ctype,jname:jname};},
        peg$c41 = "\\",
        peg$c42 = { type: "literal", value: "\\", description: "\"\\\\\"" },
        peg$c43 = { type: "any", description: "any character" },
        peg$c44 = "\"",
        peg$c45 = { type: "literal", value: "\"", description: "\"\\\"\"" },
        peg$c46 = /^[^"]/,
        peg$c47 = { type: "class", value: "[^\"]", description: "[^\"]" },
        peg$c48 = "*",
        peg$c49 = { type: "literal", value: "*", description: "\"*\"" },
        peg$c50 = ":",
        peg$c51 = { type: "literal", value: ":", description: "\":\"" },
        peg$c52 = "select",
        peg$c53 = { type: "literal", value: "select", description: "\"select\"" },
        peg$c54 = "from",
        peg$c55 = { type: "literal", value: "from", description: "\"from\"" },

        peg$currPos          = 0,
        peg$reportedPos      = 0,
        peg$cachedPos        = 0,
        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
        peg$maxFailPos       = 0,
        peg$maxFailExpected  = [],
        peg$silentFails      = 0,

        peg$result;

    if ("startRule" in options) {
      if (!(options.startRule in peg$startRuleFunctions)) {
        throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
      }

      peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
    }

    function text() {
      return input.substring(peg$reportedPos, peg$currPos);
    }

    function offset() {
      return peg$reportedPos;
    }

    function line() {
      return peg$computePosDetails(peg$reportedPos).line;
    }

    function column() {
      return peg$computePosDetails(peg$reportedPos).column;
    }

    function expected(description) {
      throw peg$buildException(
        null,
        [{ type: "other", description: description }],
        peg$reportedPos
      );
    }

    function error(message) {
      throw peg$buildException(message, null, peg$reportedPos);
    }

    function peg$computePosDetails(pos) {
      function advance(details, startPos, endPos) {
        var p, ch;

        for (p = startPos; p < endPos; p++) {
          ch = input.charAt(p);
          if (ch === "\n") {
            if (!details.seenCR) { details.line++; }
            details.column = 1;
            details.seenCR = false;
          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
            details.line++;
            details.column = 1;
            details.seenCR = true;
          } else {
            details.column++;
            details.seenCR = false;
          }
        }
      }

      if (peg$cachedPos !== pos) {
        if (peg$cachedPos > pos) {
          peg$cachedPos = 0;
          peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
        }
        advance(peg$cachedPosDetails, peg$cachedPos, pos);
        peg$cachedPos = pos;
      }

      return peg$cachedPosDetails;
    }

    function peg$fail(expected) {
      if (peg$currPos < peg$maxFailPos) { return; }

      if (peg$currPos > peg$maxFailPos) {
        peg$maxFailPos = peg$currPos;
        peg$maxFailExpected = [];
      }

      peg$maxFailExpected.push(expected);
    }

    function peg$buildException(message, expected, pos) {
      function cleanupExpected(expected) {
        var i = 1;

        expected.sort(function(a, b) {
          if (a.description < b.description) {
            return -1;
          } else if (a.description > b.description) {
            return 1;
          } else {
            return 0;
          }
        });

        while (i < expected.length) {
          if (expected[i - 1] === expected[i]) {
            expected.splice(i, 1);
          } else {
            i++;
          }
        }
      }

      function buildMessage(expected, found) {
        function stringEscape(s) {
          function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }

          return s
            .replace(/\\/g,   '\\\\')
            .replace(/"/g,    '\\"')
            .replace(/\x08/g, '\\b')
            .replace(/\t/g,   '\\t')
            .replace(/\n/g,   '\\n')
            .replace(/\f/g,   '\\f')
            .replace(/\r/g,   '\\r')
            .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
            .replace(/[\x10-\x1F\x80-\xFF]/g,    function(ch) { return '\\x'  + hex(ch); })
            .replace(/[\u0180-\u0FFF]/g,         function(ch) { return '\\u0' + hex(ch); })
            .replace(/[\u1080-\uFFFF]/g,         function(ch) { return '\\u'  + hex(ch); });
        }

        var expectedDescs = new Array(expected.length),
            expectedDesc, foundDesc, i;

        for (i = 0; i < expected.length; i++) {
          expectedDescs[i] = expected[i].description;
        }

        expectedDesc = expected.length > 1
          ? expectedDescs.slice(0, -1).join(", ")
              + " or "
              + expectedDescs[expected.length - 1]
          : expectedDescs[0];

        foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";

        return "Expected " + expectedDesc + " but " + foundDesc + " found.";
      }

      var posDetails = peg$computePosDetails(pos),
          found      = pos < input.length ? input.charAt(pos) : null;

      if (expected !== null) {
        cleanupExpected(expected);
      }

      return new SyntaxError(
        message !== null ? message : buildMessage(expected, found),
        expected,
        found,
        pos,
        posDetails.line,
        posDetails.column
      );
    }

    function peg$parsestart() {
      var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;

      s0 = peg$currPos;
      s1 = peg$parsews();
      if (s1 === peg$FAILED) {
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        s2 = peg$parseselect();
        if (s2 !== peg$FAILED) {
          s3 = peg$parsews();
          if (s3 === peg$FAILED) {
            s3 = peg$c1;
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parseroot_call();
            if (s4 !== peg$FAILED) {
              s5 = peg$parseblock();
              if (s5 !== peg$FAILED) {
                s6 = peg$parsews();
                if (s6 === peg$FAILED) {
                  s6 = peg$c1;
                }
                if (s6 !== peg$FAILED) {
                  s7 = peg$parsefrom();
                  if (s7 !== peg$FAILED) {
                    s8 = peg$parsews();
                    if (s8 === peg$FAILED) {
                      s8 = peg$c1;
                    }
                    if (s8 !== peg$FAILED) {
                      s9 = peg$parseanything();
                      if (s9 !== peg$FAILED) {
                        peg$reportedPos = s0;
                        s1 = peg$c2(s4, s5, s9);
                        s0 = s1;
                      } else {
                        peg$currPos = s0;
                        s0 = peg$c0;
                      }
                    } else {
                      peg$currPos = s0;
                      s0 = peg$c0;
                    }
                  } else {
                    peg$currPos = s0;
                    s0 = peg$c0;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$c0;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$c0;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c0;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseroot_call() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$parsews();
      if (s1 === peg$FAILED) {
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        s2 = peg$parsecall();
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c3(s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parsecalls() {
      var s0, s1, s2, s3, s4;

      s0 = peg$currPos;
      s1 = [];
      s2 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 46) {
        s3 = peg$c5;
        peg$currPos++;
      } else {
        s3 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c6); }
      }
      if (s3 !== peg$FAILED) {
        s4 = peg$parsecall();
        if (s4 !== peg$FAILED) {
          peg$reportedPos = s2;
          s3 = peg$c7(s4);
          s2 = s3;
        } else {
          peg$currPos = s2;
          s2 = peg$c0;
        }
      } else {
        peg$currPos = s2;
        s2 = peg$c0;
      }
      if (s2 !== peg$FAILED) {
        while (s2 !== peg$FAILED) {
          s1.push(s2);
          s2 = peg$currPos;
          if (input.charCodeAt(peg$currPos) === 46) {
            s3 = peg$c5;
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c6); }
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parsecall();
            if (s4 !== peg$FAILED) {
              peg$reportedPos = s2;
              s3 = peg$c7(s4);
              s2 = s3;
            } else {
              peg$currPos = s2;
              s2 = peg$c0;
            }
          } else {
            peg$currPos = s2;
            s2 = peg$c0;
          }
        }
      } else {
        s1 = peg$c0;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c8(s1);
      }
      s0 = s1;

      return s0;
    }

    function peg$parsecall() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$parseidentifier();
      if (s1 !== peg$FAILED) {
        s2 = peg$parsecall_parameters();
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c9(s1, s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parsecall_parameters() {
      var s0, s1, s2, s3, s4, s5;

      s0 = peg$currPos;
      s1 = peg$parsews();
      if (s1 === peg$FAILED) {
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        if (input.charCodeAt(peg$currPos) === 40) {
          s2 = peg$c10;
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c11); }
        }
        if (s2 !== peg$FAILED) {
          s3 = peg$parsews();
          if (s3 === peg$FAILED) {
            s3 = peg$c1;
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parseparameter_list();
            if (s4 === peg$FAILED) {
              s4 = peg$c1;
            }
            if (s4 !== peg$FAILED) {
              if (input.charCodeAt(peg$currPos) === 41) {
                s5 = peg$c12;
                peg$currPos++;
              } else {
                s5 = peg$FAILED;
                if (peg$silentFails === 0) { peg$fail(peg$c13); }
              }
              if (s5 !== peg$FAILED) {
                peg$reportedPos = s0;
                s1 = peg$c14(s4);
                s0 = s1;
              } else {
                peg$currPos = s0;
                s0 = peg$c0;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c0;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseparameter_list() {
      var s0, s1, s2, s3, s4, s5, s6, s7, s8;

      s0 = peg$currPos;
      s1 = peg$currPos;
      s2 = peg$parsestr_parameter();
      if (s2 !== peg$FAILED) {
        s3 = [];
        s4 = peg$currPos;
        s5 = peg$parsews();
        if (s5 === peg$FAILED) {
          s5 = peg$c1;
        }
        if (s5 !== peg$FAILED) {
          s6 = peg$parseproperty_separator();
          if (s6 !== peg$FAILED) {
            s7 = peg$parsews();
            if (s7 === peg$FAILED) {
              s7 = peg$c1;
            }
            if (s7 !== peg$FAILED) {
              s8 = peg$parsestr_parameter();
              if (s8 !== peg$FAILED) {
                peg$reportedPos = s4;
                s5 = peg$c15(s8);
                s4 = s5;
              } else {
                peg$currPos = s4;
                s4 = peg$c0;
              }
            } else {
              peg$currPos = s4;
              s4 = peg$c0;
            }
          } else {
            peg$currPos = s4;
            s4 = peg$c0;
          }
        } else {
          peg$currPos = s4;
          s4 = peg$c0;
        }
        while (s4 !== peg$FAILED) {
          s3.push(s4);
          s4 = peg$currPos;
          s5 = peg$parsews();
          if (s5 === peg$FAILED) {
            s5 = peg$c1;
          }
          if (s5 !== peg$FAILED) {
            s6 = peg$parseproperty_separator();
            if (s6 !== peg$FAILED) {
              s7 = peg$parsews();
              if (s7 === peg$FAILED) {
                s7 = peg$c1;
              }
              if (s7 !== peg$FAILED) {
                s8 = peg$parsestr_parameter();
                if (s8 !== peg$FAILED) {
                  peg$reportedPos = s4;
                  s5 = peg$c15(s8);
                  s4 = s5;
                } else {
                  peg$currPos = s4;
                  s4 = peg$c0;
                }
              } else {
                peg$currPos = s4;
                s4 = peg$c0;
              }
            } else {
              peg$currPos = s4;
              s4 = peg$c0;
            }
          } else {
            peg$currPos = s4;
            s4 = peg$c0;
          }
        }
        if (s3 !== peg$FAILED) {
          s4 = peg$parsews();
          if (s4 === peg$FAILED) {
            s4 = peg$c1;
          }
          if (s4 !== peg$FAILED) {
            peg$reportedPos = s1;
            s2 = peg$c16(s2, s3);
            s1 = s2;
          } else {
            peg$currPos = s1;
            s1 = peg$c0;
          }
        } else {
          peg$currPos = s1;
          s1 = peg$c0;
        }
      } else {
        peg$currPos = s1;
        s1 = peg$c0;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c17(s1);
      }
      s0 = s1;

      return s0;
    }

    function peg$parsestr_parameter() {
      var s0, s1, s2, s3;

      s0 = peg$currPos;
      s1 = peg$parseparameter();
      if (s1 !== peg$FAILED) {
        s2 = peg$parsesplit();
        if (s2 !== peg$FAILED) {
          s3 = peg$parsestring_literal();
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c18(s1, s3);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseparameter() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = [];
      if (peg$c19.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c20); }
      }
      if (s2 !== peg$FAILED) {
        while (s2 !== peg$FAILED) {
          s1.push(s2);
          if (peg$c19.test(input.charAt(peg$currPos))) {
            s2 = input.charAt(peg$currPos);
            peg$currPos++;
          } else {
            s2 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c20); }
          }
        }
      } else {
        s1 = peg$c0;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c21(s1);
      }
      s0 = s1;

      return s0;
    }

    function peg$parseblock() {
      var s0, s1, s2, s3, s4, s5, s6, s7;

      s0 = peg$currPos;
      s1 = peg$parsews();
      if (s1 === peg$FAILED) {
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        if (input.charCodeAt(peg$currPos) === 123) {
          s2 = peg$c22;
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c23); }
        }
        if (s2 !== peg$FAILED) {
          s3 = peg$parsews();
          if (s3 === peg$FAILED) {
            s3 = peg$c1;
          }
          if (s3 !== peg$FAILED) {
            s4 = peg$parseproperties();
            if (s4 !== peg$FAILED) {
              s5 = peg$parsews();
              if (s5 === peg$FAILED) {
                s5 = peg$c1;
              }
              if (s5 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 125) {
                  s6 = peg$c24;
                  peg$currPos++;
                } else {
                  s6 = peg$FAILED;
                  if (peg$silentFails === 0) { peg$fail(peg$c25); }
                }
                if (s6 !== peg$FAILED) {
                  s7 = peg$parsews();
                  if (s7 === peg$FAILED) {
                    s7 = peg$c1;
                  }
                  if (s7 !== peg$FAILED) {
                    peg$reportedPos = s0;
                    s1 = peg$c26(s4);
                    s0 = s1;
                  } else {
                    peg$currPos = s0;
                    s0 = peg$c0;
                  }
                } else {
                  peg$currPos = s0;
                  s0 = peg$c0;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$c0;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c0;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseproperties() {
      var s0, s1, s2, s3, s4, s5, s6, s7;

      s0 = peg$currPos;
      s1 = peg$currPos;
      s2 = peg$parseproperty();
      if (s2 !== peg$FAILED) {
        s3 = [];
        s4 = peg$currPos;
        s5 = peg$parseproperty_separator();
        if (s5 !== peg$FAILED) {
          s6 = peg$parsews();
          if (s6 === peg$FAILED) {
            s6 = peg$c1;
          }
          if (s6 !== peg$FAILED) {
            s7 = peg$parseproperty();
            if (s7 !== peg$FAILED) {
              peg$reportedPos = s4;
              s5 = peg$c15(s7);
              s4 = s5;
            } else {
              peg$currPos = s4;
              s4 = peg$c0;
            }
          } else {
            peg$currPos = s4;
            s4 = peg$c0;
          }
        } else {
          peg$currPos = s4;
          s4 = peg$c0;
        }
        while (s4 !== peg$FAILED) {
          s3.push(s4);
          s4 = peg$currPos;
          s5 = peg$parseproperty_separator();
          if (s5 !== peg$FAILED) {
            s6 = peg$parsews();
            if (s6 === peg$FAILED) {
              s6 = peg$c1;
            }
            if (s6 !== peg$FAILED) {
              s7 = peg$parseproperty();
              if (s7 !== peg$FAILED) {
                peg$reportedPos = s4;
                s5 = peg$c15(s7);
                s4 = s5;
              } else {
                peg$currPos = s4;
                s4 = peg$c0;
              }
            } else {
              peg$currPos = s4;
              s4 = peg$c0;
            }
          } else {
            peg$currPos = s4;
            s4 = peg$c0;
          }
        }
        if (s3 !== peg$FAILED) {
          peg$reportedPos = s1;
          s2 = peg$c16(s2, s3);
          s1 = s2;
        } else {
          peg$currPos = s1;
          s1 = peg$c0;
        }
      } else {
        peg$currPos = s1;
        s1 = peg$c0;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c27(s1);
      }
      s0 = s1;

      return s0;
    }

    function peg$parseproperty() {
      var s0;

      s0 = peg$parsecall_property();
      if (s0 === peg$FAILED) {
        s0 = peg$parseobject_property();
        if (s0 === peg$FAILED) {
          s0 = peg$parsecol_property();
          if (s0 === peg$FAILED) {
            s0 = peg$parsesimple_property();
          }
        }
      }

      return s0;
    }

    function peg$parsesimple_property() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$parseidentifier();
      if (s1 !== peg$FAILED) {
        s2 = peg$parsews();
        if (s2 === peg$FAILED) {
          s2 = peg$c1;
        }
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c28(s1);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseobject_property() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = peg$parseidentifier();
      if (s1 !== peg$FAILED) {
        s2 = peg$parseblock();
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c29(s1, s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parsecall_property() {
      var s0, s1, s2, s3;

      s0 = peg$currPos;
      s1 = peg$parseidentifier();
      if (s1 !== peg$FAILED) {
        s2 = peg$parsecalls();
        if (s2 !== peg$FAILED) {
          s3 = peg$parseblock();
          if (s3 !== peg$FAILED) {
            peg$reportedPos = s0;
            s1 = peg$c30(s1, s2, s3);
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseproperty_separator() {
      var s0;

      if (input.charCodeAt(peg$currPos) === 44) {
        s0 = peg$c31;
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c32); }
      }

      return s0;
    }

    function peg$parseidentifier() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = [];
      if (peg$c33.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c34); }
      }
      if (s2 !== peg$FAILED) {
        while (s2 !== peg$FAILED) {
          s1.push(s2);
          if (peg$c33.test(input.charAt(peg$currPos))) {
            s2 = input.charAt(peg$currPos);
            peg$currPos++;
          } else {
            s2 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c34); }
          }
        }
      } else {
        s1 = peg$c0;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c35(s1);
      }
      s0 = s1;

      return s0;
    }

    function peg$parsews() {
      var s0, s1;

      peg$silentFails++;
      s0 = [];
      if (peg$c37.test(input.charAt(peg$currPos))) {
        s1 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c38); }
      }
      while (s1 !== peg$FAILED) {
        s0.push(s1);
        if (peg$c37.test(input.charAt(peg$currPos))) {
          s1 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c38); }
        }
      }
      peg$silentFails--;
      if (s0 === peg$FAILED) {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c36); }
      }

      return s0;
    }

    function peg$parsecol_property() {
      var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;

      s0 = peg$currPos;
      s1 = peg$parseidentifier();
      if (s1 !== peg$FAILED) {
        s2 = peg$parsedot();
        if (s2 !== peg$FAILED) {
          s3 = peg$parseidentifier();
          if (s3 !== peg$FAILED) {
            s4 = peg$parsews();
            if (s4 !== peg$FAILED) {
              s5 = peg$currPos;
              s6 = peg$parsesplit();
              if (s6 !== peg$FAILED) {
                s7 = peg$parsews();
                if (s7 !== peg$FAILED) {
                  s8 = peg$parseidentifier();
                  if (s8 !== peg$FAILED) {
                    s9 = peg$parsews();
                    if (s9 !== peg$FAILED) {
                      peg$reportedPos = s5;
                      s6 = peg$c39(s8);
                      s5 = s6;
                    } else {
                      peg$currPos = s5;
                      s5 = peg$c0;
                    }
                  } else {
                    peg$currPos = s5;
                    s5 = peg$c0;
                  }
                } else {
                  peg$currPos = s5;
                  s5 = peg$c0;
                }
              } else {
                peg$currPos = s5;
                s5 = peg$c0;
              }
              if (s5 === peg$FAILED) {
                s5 = peg$c1;
              }
              if (s5 !== peg$FAILED) {
                s6 = peg$parseidentifier();
                if (s6 !== peg$FAILED) {
                  peg$reportedPos = s0;
                  s1 = peg$c40(s1, s3, s5, s6);
                  s0 = s1;
                } else {
                  peg$currPos = s0;
                  s0 = peg$c0;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$c0;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$c0;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parseescape_char() {
      var s0, s1, s2;

      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 92) {
        s1 = peg$c41;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c42); }
      }
      if (s1 !== peg$FAILED) {
        if (input.length > peg$currPos) {
          s2 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s2 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c43); }
        }
        if (s2 !== peg$FAILED) {
          s1 = [s1, s2];
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parsestring_literal() {
      var s0, s1, s2, s3;

      s0 = peg$currPos;
      if (input.charCodeAt(peg$currPos) === 34) {
        s1 = peg$c44;
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c45); }
      }
      if (s1 !== peg$FAILED) {
        s2 = [];
        s3 = peg$parseescape_char();
        if (s3 === peg$FAILED) {
          if (peg$c46.test(input.charAt(peg$currPos))) {
            s3 = input.charAt(peg$currPos);
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c47); }
          }
        }
        while (s3 !== peg$FAILED) {
          s2.push(s3);
          s3 = peg$parseescape_char();
          if (s3 === peg$FAILED) {
            if (peg$c46.test(input.charAt(peg$currPos))) {
              s3 = input.charAt(peg$currPos);
              peg$currPos++;
            } else {
              s3 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c47); }
            }
          }
        }
        if (s2 !== peg$FAILED) {
          if (input.charCodeAt(peg$currPos) === 34) {
            s3 = peg$c44;
            peg$currPos++;
          } else {
            s3 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c45); }
          }
          if (s3 !== peg$FAILED) {
            s1 = [s1, s2, s3];
            s0 = s1;
          } else {
            peg$currPos = s0;
            s0 = peg$c0;
          }
        } else {
          peg$currPos = s0;
          s0 = peg$c0;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c0;
      }

      return s0;
    }

    function peg$parsedot() {
      var s0;

      if (input.charCodeAt(peg$currPos) === 46) {
        s0 = peg$c5;
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c6); }
      }

      return s0;
    }

    function peg$parsestar() {
      var s0;

      if (input.charCodeAt(peg$currPos) === 42) {
        s0 = peg$c48;
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c49); }
      }

      return s0;
    }

    function peg$parsequote() {
      var s0;

      if (input.charCodeAt(peg$currPos) === 34) {
        s0 = peg$c44;
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c45); }
      }

      return s0;
    }

    function peg$parsesplit() {
      var s0;

      if (input.charCodeAt(peg$currPos) === 58) {
        s0 = peg$c50;
        peg$currPos++;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c51); }
      }

      return s0;
    }

    function peg$parseselect() {
      var s0;

      if (input.substr(peg$currPos, 6) === peg$c52) {
        s0 = peg$c52;
        peg$currPos += 6;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c53); }
      }

      return s0;
    }

    function peg$parsefrom() {
      var s0;

      if (input.substr(peg$currPos, 4) === peg$c54) {
        s0 = peg$c54;
        peg$currPos += 4;
      } else {
        s0 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c55); }
      }

      return s0;
    }

    function peg$parseanything() {
      var s0, s1;

      s0 = [];
      if (input.length > peg$currPos) {
        s1 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c43); }
      }
      while (s1 !== peg$FAILED) {
        s0.push(s1);
        if (input.length > peg$currPos) {
          s1 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s1 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c43); }
        }
      }

      return s0;
    }

    peg$result = peg$startRuleFunction();

    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
      return peg$result;
    } else {
      if (peg$result !== peg$FAILED && peg$currPos < input.length) {
        peg$fail({ type: "end", description: "end of input" });
      }

      throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
    }
  }

  return {
    SyntaxError: SyntaxError,
    parse:       parse
  };
});
</script>
  <script>



    function displayDate() {
      var str1 = $("#t1").val();
      var str2 = $("#t2").val();
      var result1 = formatObject(str1);
      var result2 = formatContent(str2);
      var result = result1.map(item => {
        let obj = { name: item };
        obj.content = result2;
        return obj;
      });
      $("#result").text(JSON.stringify(result));
    }




    const beanTpl = `
package #{packageName}

import java.io.Serializable;

@Data
public class #{className} implements Serializable {
	#{fields}
}
`;

    const xmlTpl = `
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="#{packageName}">
	#{body}
</mapper>
`


const resultMapperTpl = `
<resultMap id="#{method}" type="#{bean}">
    #{fields}
  </resultMap>
`;


const mapperTpl = `
#{import}
public interface #{mapperName}{
  #{methods}
}
`;

const selectTpl = `
<select id="#{method}" resultMap="#{method}">
  #{sql}
</select>
`;

function toHump(name) {
    return name.replace(/\_(\w)/g, function(all, letter){
        return letter.toUpperCase();
    });
}
// 驼峰转换下划线
function toLine(name) {
  return name.replace(/([A-Z])/g,"_$1").toLowerCase();
}

function toHumpUpper(name) {
  return upper(toHump(name));
}

function upper(str){
 var strTemp = ""; //新字符串
 for(var i=0;i<str.length;i++){
  if(i == 0){
   strTemp += str[i].toUpperCase(); //第一个
   continue;
  }
  if(str[i] == " " && i< str.length-1){ //空格后
   strTemp += " ";
   strTemp += str[i+1].toUpperCase();
   i++;
   continue;
  }
  strTemp += str[i];
 }
  return strTemp;
 }


    
 function genSql(ast){

let cols = [];

let rootMap = this.getDupMap(ast);

function walkTree(tree,res){
  tree.properties.forEach(i=>{
    if(i.calls){
      let sres = [];
      walkTree(i.properties,sres)
      res.push(...sres)
    }else{
      res.push(`${i.alias}.${i.name}`)
    }
  })
}

ast.properties.forEach(i=>{
  if(i.calls){
    let res = [];
    walkTree(i.properties,res)
    cols.push(...res)
  }else{
    let name = `${i.alias}.${i.name}`
    cols.push(name);
  }

})

cols = cols.map(i=>{
   if(rootMap[i]){
       //与其他字段重复
       return `${i} as ${rootMap[i]}`
   }
   return i;
})

return render(selectTpl,{
      method: ast.call,
      sql:`select ${cols.join(',')} from ${ast.querybody}`
    });
}
function getDupMap(ast){
  let colNameMap = {};
  let cols = [];
  let dupMap = {};
  function genAlias(ali,name){
      return ali+name+'_1'
  }

  function walkTree(tree,res){
      tree.properties.forEach(i=>{
        if(i.calls){
          let sres = [];
          walkTree(i.properties,sres)
          res.push(...sres)
        }else{
           if(colNameMap[i.name]){
            //重复
            dupMap[`${i.alias}.${i.name}`] = genAlias(i.alias,i.name)
           }else{
            colNameMap[i.name]=true
           }
          res.push(`${i.alias}.${i.name}`)
        }
      })
    }

    ast.properties.forEach(i=>{
      if(i.calls){
        let res = [];
        walkTree(i.properties,res)
        cols.push(...res)
      }else{
        let name = `${i.alias}.${i.name}`
        if(colNameMap[i.name]){
            //重复字段
            //添加 as 别名
            dupMap[`${i.alias}.${i.name}`] = genAlias(i.alias,i.name)
        }else{
            colNameMap[i.name]=true
        }

        cols.push(name);
      }
    })
    console.log(dupMap)
    return dupMap;
} 
function genResultMapper(ast){
let rows = [];

let rootMap = this.getDupMap(ast);
ast.properties.forEach(prop=>{
   let colName = prop.name;
   if(rootMap[`${prop.alias}.${prop.name}`]){
       //与其他字段重复
       colName = rootMap[prop.name]
   }
  if(prop.calls){
    this.genSubMapperRow(prop,rootMap,rows);
  }else{
    let jname = prop.jname?prop.jname:this.toHump(prop.name)
    rows.push(`<result property="${jname}" column="${colName}"></result>`);
  }
})
return {
    method:ast.call,
    bean:ast.parameters.find(i=>i.name=='type').value,
    fields:rows
  }
}
	

	function genBean(rootBean,res){
    let packageName = rootBean.package;
    let cName = rootBean.cName;
    let fields = []
    for(var bean of rootBean.fields){
      if(bean.fields){
        //生成关联类
        packageName=packageName+";\n"+`import ${bean.package}.${bean.cName};`;
        genBean(bean,res)
      }
      fields.push(`private ${bean.type} ${bean.name};`)
    }

    res.push(
      render(beanTpl,{
        packageName,
        className:cName,
        fields:fields.join("\n\n")
      })
    )
  }
	
	function genResultMapper(ast){
    let rows = [];

        let rootMap = this.getDupMap(ast);
        ast.properties.forEach(prop=>{
           let colName = prop.name;
           if(rootMap[`${prop.alias}.${prop.name}`]){
               //与其他字段重复
               colName = rootMap[prop.name]
           }
          if(prop.calls){
            this.genSubMapperRow(prop,rootMap,rows);
          }else{
            let jname = prop.jname?prop.jname:this.toHump(prop.name)
            rows.push(`<result property="${jname}" column="${colName}"></result>`);
          }
        })
    return render(resultMapperTpl,{
        method:ast.call,
        bean:ast.parameters.find(i=>i.name=='type').value,
        fields:rows.join("\n")
      })
  }
  function genInnerMapperRow(props,rootMap){
        return props.map(prop=>{
          if(prop.calls){
              let srows=[];
              this.genSubMapperRow(prop,rootMap,srows);
              return "\t"+srows.join("\n");
          }
          let colName = prop.name;
          let key = `${prop.alias}.${prop.name}`;
          if(rootMap[key]){
              //与其他字段重复
              colName = rootMap[key]
          }
          let jname = prop.jname?prop.jname:this.toHump(prop.name)
          return `<result property="${jname}" column="${colName}"></result>`;
        });
      } 
	  function genSubMapperRow(prop,rootMap,rows){
          if(prop.calls){
           let srows = [];
           let config = this.toMap(prop.calls.find(i=>i.call=='config').parameters);
           if(config.fetch=='list'){
             srows.push(`<collection property="${prop.name}" ofType="${config.type}">`);
             srows.push(...this.genInnerMapperRow(prop.properties.properties,rootMap));
             srows.push(`</collection>`);
           }else{
             srows.push(`<association property="${prop.name}" javaType="${config.type}">`);
             srows.push(...this.genInnerMapperRow(prop.properties.properties,rootMap));
             srows.push(`</association>`)
           }
           rows.push(...srows);
         }else{
           let jname = prop.jname?prop.jname:this.toHump(prop.name)
           rows.push(`<result property="${jname}" column="${colName}"></result>`);
         }
      }

  function genMapperRow(props){
    //TODO 是否能够嵌套？
    return props.map(prop=>{
      let jname = prop.jname?prop.jname:toHump(prop.name)
      return `<result property="${jname}" column="${prop.alias}.${prop.name}"></result>`;
    });
  }


  function genMapper(ast){
    let method = ast.call;
    let importPack = [];
    let fullName = ast.parameters.find(i=>i.name=='type').value;
    let {package,cName} = getClass(fullName);
    importPack.push('import '+fullName+';');
    let fetch = ast.parameters.find(i=>i.name=='fetch');
    let type = fetch?fetch.value:'obj';
    let jtype = type=='list'?`List<${cName}>`:cName
    if(type=='list'){
      importPack.push('import java.util.List;');
    }
    let mn = `${jtype} ${method}();`
    return render(mapperTpl,{
      mapperName:'xxMapper',
      methods:mn,
      import:importPack.join("\n")
    })
  }
  
  function getClass(fname){
    return {
      package:fname.substring(0,fname.lastIndexOf('.')),
      cName:fname.substring(fname.lastIndexOf('.')+1)
    }
  }
	
  
  function gen(ast){
    let fields = genProp(ast.properties)
    let rootFName = ast.parameters.find(i=>i.name=='type').value;
    let classInfo = getClass(rootFName)
    let rootBean = {...classInfo,fields}
    //生成rootbean
    return rootBean;
  }

  function genProp(props){
    return props.map(p=>{
      if(p.calls){
        return genSub(p);
      }
      return {
        name: p.jname?p.jname:toHump(p.name),
        tname: p.name,
        type: p.type
      }
    });
  }

  function toMap(parameters){
    return parameters.reduce((t,c)=>{
      t[c.name]=c.value
      return t;
    },{});
  }


  function genSub(subBean){
    let rootFName = subBean.calls[0].parameters.find(i=>i.name=='type').value;
    let config = subBean.calls[0].parameters.reduce((t,c)=>{
      t[c.name]=c.value
      return t;
    },{});

    let fetchType = config.fetch;
    let beanName = config.type;
    let {package,cName} = getClass(beanName)
    let humpName = toHump(cName)
    return {
      name: subBean.name,
      beanName,
      package,
      cName,
      fields:genProp(subBean.properties.properties),
      type: fetchType=='list'?`List<${cName}>`:cName
    }
  }



	
	
	
	function parseQl(v){
     return parser.parse(v);
	}


  function genCode(ast){
    let rootBean = gen(ast);
    let beans = [];
    genBean(rootBean,beans);
    let mapper = genMapper(ast)
    let resultMap = genResultMapper(ast)
    let sql = genSql(ast)
    return [mapper,resultMap,sql,beans.join("\n")]
  }



    function render(template, context) {

      var tokenReg = /(\\)?#\{([^\{\}\\]+)(\\)?\}/g;

      return template.replace(tokenReg, function (word, slash1, token, slash2) {
        if (slash1 || slash2) {
          return word.replace('\\', '');
        }

        var variables = token.replace(/\s/g, '').split('.');
        var currentObject = context;
        var i, length, variable;

        for (i = 0, length = variables.length, variable = variables[i]; i < length; ++i) {
          currentObject = currentObject[variable];
          if (currentObject === undefined || currentObject === null) return '';
        }

        return currentObject;
      })
    }


    $(function () {

      var demo=`select 
findByRootIdOrClassId(type:"vip.youngboy.model.TplClass") {
  b.id Long,
  b.class_name:className String,
  b.p_name:pName String,
  c.rootId Long,
  components.config(type:"vip.youngboy.model.TplModuleInfo",fetch:"list"){
    a.id Long,
    a.component:component String,
    a.name String,
    subList.config(type:"vip.youngboy.model.TplModuleItem",fetch:"list"){
      d.id Long,
      d.name String
    }
  
  }
} 
from
	tpl_class_info b
    join tpl_class_rel c ON b.id = c.classId
    join tpl_module_info a ON a.id = c.modId join tpl_module_item d.mid=c.id`

    $('#t1').val(demo);

    var handle = function () {
        let v1 = $('#t1').val()
        let ast = parseQl(v1)
        console.log(ast)
        let res = genCode(ast)
        console.log(res)
         $('#t2').val(res.join("\n\n"))
      };

      handle()

      $('#button').click(handle)

    })


  </script>
</head>
<style>


.container{
  display: flex;
  justify-content : space-between;
  align-items : center; 
}

.container .textbox{
  width:48%;
}

.buttonbox{
  width: 4%;
  text-align: center;
}

.container div textarea{
  width:100%;
  height:380px;
}


.gitee{
  width: 50%;
  margin-top: 60px;
  text-align: center;
}

</style>
<body>
  <h2>类graphql+sql 自定义语法生成mybatis 一对多 一对一级联查询代码（支持多层级联）</h2>
  <h3>使用说明：左边框使用自定义语法定义结构，点击转换按钮在右边框查看结果</h3>
  <h4>Blog:  <a href="https:youngboy.vip">https:youngboy.vip</a></h4>

  <div class="container">
    <div class="textbox"><textarea id="t1"></textarea></div>
    <div class="buttonbox"><button id="button" type="button">转换</button></div>
    <div class="textbox"><textarea id="t2"></textarea></div>
  </div>

  <h2>语法示例</h2>
  <div class="container">
    
    <div style="width: 50%;">
      <pre>
        select 
          findByRootIdOrClassId(type:"vip.youngboy.model.TplClass") {
            b.id Long,
            b.class_name:className String,
            b.p_name:pName String,
            c.rootId Long,
            components.config(type:"vip.youngboy.model.TplModuleInfo",fetch:"list"){
              a.id Long,
              a.component:component String,
              a.name String,
              subList.config(type:"vip.youngboy.model.TplModuleItem",fetch:"list"){
                d.id Long,
                d.name String
              }
            }
          } 
          from
        tpl_class_info b
        join tpl_class_rel c ON b.id = c.classId
        join tpl_module_info a ON a.id = c.modId join tpl_module_item d.mid=c.id
      </pre>
    </div>
    
    <div class="gitee">
      <a href='https://gitee.com/youngboyvip/mybatis-plus-generator-ui'><img src='https://gitee.com/youngboyvip/mybatis-plus-generator-ui/widgets/widget_2.svg' alt='Fork me on Gitee'></img></a>
      <a href='https://gitee.com/youngboyvip/graphqljs'><img src='https://gitee.com/youngboyvip/graphqljs/widgets/widget_2.svg' alt='Fork me on Gitee'></img></a>
    </div>
  </div>

  
</body>

</html>